/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       main_menu.cpp

	$Header: /game/main_menu.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "main_menu.h"

#include <string>

#include <fstream>
#include <strstream>
#include "adventure_ai.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "adventure_map_window.h"
#include "adventure_map_window_ptr.h"
#include "adventure_sounds.h"
#include "animated_window.h"
#include "animation_cache.h"
#include "basic_dialog.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bitmap_raw.h"
#include "bitmap_raw_cache.h"
#include "bitmap_raw_ptr.h"
#include "bitmap_raw_window.h"
#include "bound_handler.h"
#include "button.h"
#include "campaign_file_header.h"
#include "carryover_data.h"
#include "compressed_filter.h"
#include "debug_message.h"
#include "dialog_campaign_selection.h"
#include "dialog_campaign.h"
#include "dialog_high_score.h"
#include "dialog_load_game.h"
#include "enum_operations.h"
#include "external_string.h"
#include "function_handler.h"
#include "game_application.h"
#include "high_scores.h"
#include "interface_help.h"
#include "item_help_block.h"
#include "map_header.h"
#include "memory_window.h"
#include "music.h"
#include "new_map_dialog.h"
#include "new_map_options_dialog.h"
#include "new_game_details.h"
#include "options_dialog.h"
#include "platform.h"
#include "player.h"
#include "progress_bar_dialog.h"
#include "progress_handler.h"
#include "replace_keywords.h"
#include "resource.h"
#include "scroll_menu.h"
#include "saved_combat.h"
#include "simple_dialog.h"
#include "sound_cache.h"
#include "standard_fonts.h"
#include "text_window.h"
#include "town_type.h"


// Used by read_new_game and read_saved_game
extern t_external_string const k_text_open_failure;

extern t_sound_cache const k_main_menu_music( "main_menu" );

namespace
{
	static t_bitmap_group_cache const k_bitmaps_800( "menu.main.0800" );
	static t_bitmap_group_cache const k_bitmaps_1024( "menu.main.1024" );
	static t_bitmap_group_cache const k_bitmaps_1280( "menu.main.1280" );

	static t_bitmap_raw_cache	const k_bitmap_raw_800( "menu.main.0800" );
	static t_bitmap_raw_cache	const k_bitmap_raw_1024( "menu.main.1024" );
	static t_bitmap_raw_cache	const k_bitmap_raw_1280( "menu.main.1280" );

	// ------------------------------------------------------------------------
	// menu button which hides a still & starts an animation when highlighted
	// ------------------------------------------------------------------------
	class t_menu_button : public t_button
	{
	public:
		t_menu_button( t_screen_point point, int index, t_main_menu* parent );
		// start with no images.

	    virtual void     mouse_move( t_mouse_event const& event );
	    virtual void     mouse_leaving( t_window* old_window, t_window* new_window,
										t_mouse_event const& event );
	protected:
		t_main_menu& m_menu;
		int          m_index;
	};

	// ------------------------------------------------------------------------
	// animation which highlights a button when started 
	// ------------------------------------------------------------------------
	class t_menu_animation : public t_animated_window
	{
	public:
		t_menu_animation( t_animation_ptr const& bitmaps, t_screen_point point, 
		                  int index, int speed = 100, t_main_menu* parent = 0 );

	    virtual void     left_button_up( t_mouse_event const& event );
	    virtual void     mouse_leaving( t_window* old_window, t_window* new_window,
										t_mouse_event const& event );
	protected:
		t_main_menu& m_menu;
		int          m_index;
	};

	// ------------------------------------------------------------------------
	// still which starts an animation which highlighted
	// ------------------------------------------------------------------------
	class t_menu_still : public t_bitmap_layer_window
	{
	public:
		t_menu_still( t_bitmap_layer const* bitmap, t_screen_point point, 
					  int index, t_main_menu* parent = 0, bool use_offset = true );
	    virtual void     mouse_move( t_mouse_event const& event );

	protected:
		t_main_menu& m_menu;
		int          m_index;
	};

	// ----------------------------------------------------------------
	// class to lock one (and only one) item as animating
	// ----------------------------------------------------------------
	class t_item_locker
	{
	public:
		t_item_locker( t_main_menu::t_item* items, int index );
		~t_item_locker();
	protected:
		t_main_menu::t_item* m_items;
	};

	// ----------------------------------------------------------------
	// Retrieve the file name from a t_campaign_file_ref
	// ----------------------------------------------------------------

	class t_campaign_file_name_getter : private t_campaign_file_ref::t_accessor
	{
	public:
		std::string operator()( t_campaign_file_ref const & file_ref );

	private:
		std::string	m_result;

		virtual void access( std::string const & file_name );
	};

	std::string t_campaign_file_name_getter::operator()( t_campaign_file_ref const & file_ref )
	{
		m_result = std::string();
		file_ref.accept( *this );
		return m_result;
	}

	void t_campaign_file_name_getter::access( std::string const & file_name )
	{
		m_result = file_name;
	}
}; // unnamed namespace

// ----------------------------------------------------------------
// Create a default vector of player setup structures for campaign
// scenarios
// ----------------------------------------------------------------
static t_external_string const k_text_default_player_name( "main_menu_player.misc" );
std::vector< t_player_setup > create_default_player_setup_vector(
	t_map_header const &	map_header )
{
	std::vector< t_player_setup > result;
	bool human_player_set = false;
	t_player_color color;
	for ( color = t_player_color( 0 ); color < k_active_player_color_count; enum_incr( color ) )
	{
		if ( !map_header.playable[ color ] )
			continue;

		t_player_setup setup;

		if ( !human_player_set && map_header.can_be_human[ color ] )
		{
			setup.human = true;
			human_player_set = true;
		}
		else
			setup.human = false;

		setup.name = k_text_default_player_name;
		setup.color = color;
		setup.alignment = k_town_none;

		result.push_back( setup );
	}
	assert( !result.empty() );
	assert( human_player_set );

	return result;
}

// ----------------------------------------------------------------
// Display a message box indicating a failure to open a map file
// ----------------------------------------------------------------
void file_open_failure( t_campaign_file_ref const & file_ref )
{
	std::string file_name = t_campaign_file_name_getter()( file_ref );
	ok_dialog( replace_keywords( k_text_open_failure, "%file_name", file_name ), true );
}

extern t_animation_cache       g_sample_cursor;

void verify_external_strings()
{
	int result = t_external_string::load_all();

	if (result == 0)
		ok_dialog( "All external strings loaded.", true );
	else
		ok_dialog( format_string( "%i strings did not load.  Check missing_external_strings.txt", result ),  true );
}

// ----------------------------------------------------------------
// class to lock one (and only one) item as animating
// ----------------------------------------------------------------
t_item_locker::t_item_locker( t_main_menu::t_item* items, int index )
{
	int i;

	m_items = items;
	for (i = 0; i < t_main_menu::k_num_menu_items; i++)
	{
		items[i].set_selected( i == index );
		items[i].lock();
	}
}

t_item_locker::~t_item_locker()
{
	int i;

	for (i = 0; i < t_main_menu::k_num_menu_items; i++)
	{
		m_items[i].lock( false );
		m_items[i].set_selected( false );
	}
}

// --------------------------------------------------------
// create a button from a set of bitmaps
// --------------------------------------------------------
t_menu_button* create_menu_button( t_bitmap_group_ptr bitmaps, std::string name,
								   t_main_menu* parent,
								   t_screen_point origin, int index )
{
	t_menu_button*		  button;
	t_bitmap_layer const* layer;
	t_screen_rect         rect;

	layer = bitmaps->find( name + "_released" );
	if (layer == 0)
		return 0;

	rect = layer->get_rect();
	button = new t_menu_button( rect.top_left() - origin, index, parent );
	set_button_layers( button, bitmaps, name );
	return button;
}

// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
t_main_menu::t_item::t_item()
{
	m_button = 0;
	m_animation = 0;
	m_still = 0;
	m_text = 0;
	m_locked = false;
}

// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
void t_main_menu::t_item::set(t_button* button, t_text_window* text)
{
	m_button = button;
	m_text	 = text;
	m_locked = false;
}

// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
void t_main_menu::t_item::set_visible( bool arg )
{
	if( m_button )
		m_button->set_visible( arg );
	if( m_animation )
		m_animation->set_visible( arg );
	if( m_still )
		m_still->set_visible( arg );
	if( m_text )
		m_text->set_visible( arg );
}

// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
void t_main_menu::t_item::click()
{
	if (m_button)
		m_button->get_click_handler()( m_button );
}
	
// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
void t_main_menu::t_item::lock( bool arg )
{
	m_locked = arg;
}

// ------------------------------------------------------------------------
// group of related windows
// ------------------------------------------------------------------------
void t_main_menu::t_item::set_selected( bool arg )
{
	if (m_locked)
		return;

	if (m_button)
		m_button->set_highlighted( arg );
}

// ------------------------------------------------------------------------
// menu button which hides a still & starts an animation when highlighted
// ------------------------------------------------------------------------
t_menu_button::t_menu_button( t_screen_point point, int index, t_main_menu* parent )
			 : t_button( point, parent ), m_index( index ), m_menu(*parent)
{
}

// ------------------------------------------------------------------------
// menu button which hides a still & starts an animation when highlighted
// ------------------------------------------------------------------------
void t_menu_button::mouse_move( t_mouse_event const& event )
{
	bool was_highlighted = m_highlighted;

	t_button::mouse_move( event );
	if (!was_highlighted && m_highlighted )
	{
		m_menu.select( m_index );
	}
}

// ------------------------------------------------------------------------
// menu button which hides a still & starts an animation when highlighted
// ------------------------------------------------------------------------
void t_menu_button::mouse_leaving( t_window* old_window, t_window* new_window,
								   t_mouse_event const& event )
{
	m_menu.select( -1 );
	t_button::mouse_leaving( old_window, new_window, event );
}

// ------------------------------------------------------------------------
// animation which highlights a button when started 
// ------------------------------------------------------------------------
t_menu_animation::t_menu_animation( t_animation_ptr const& bitmaps, t_screen_point point,
								    int index, int speed, t_main_menu* parent )
				: t_animated_window( bitmaps, point, speed, parent ), m_index(index),
				  m_menu(*parent)
{
}


// ------------------------------------------------------------------------
// animation which highlights a button when started 
// ------------------------------------------------------------------------
void t_menu_animation::left_button_up( t_mouse_event const& event )
{
	m_menu.click( m_index );
}

// ------------------------------------------------------------------------
// animation which highlights a button when started 
// ------------------------------------------------------------------------
void t_menu_animation::mouse_leaving( t_window* old_window, t_window* new_window,
									  t_mouse_event const& event )
{
	m_menu.select( -1 );
}

// ------------------------------------------------------------------------
// still which starts an animation which highlighted
// ------------------------------------------------------------------------
t_menu_still::t_menu_still( t_bitmap_layer const* bitmap, t_screen_point point, 
						    int index, t_main_menu* parent, bool use_offset )
			: t_bitmap_layer_window( bitmap, point, parent, use_offset ), 
			  m_index( index ), m_menu(*parent)
{
}

// ------------------------------------------------------------------------
// still which starts an animation which highlighted
// ------------------------------------------------------------------------
void t_menu_still::mouse_move( t_mouse_event const& event )
{
	m_menu.select( m_index );
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
t_main_menu::t_main_menu( t_window* parent )
           : t_window( k_completely_transparent, parent )
{
	t_screen_rect rect = get_parent()->get_client_rect();

	init( rect );
	play_music( k_main_menu_music );

	t_mouse_window* cursor = new t_mouse_window;
	t_window*       animation = new t_animated_window( g_sample_cursor.get(), 
		                                               t_screen_point(0,0), 100, cursor );
	set_cursor( cursor );
	set_resolution( rect.width() );
	move_memory_window_to_front();	
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
t_main_menu::~t_main_menu()
{

}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::select( int index )
{
	int i;

	for (i = 0; i < k_num_menu_items; i++)
		m_items[i].set_selected( i == index );
}

void t_main_menu::click( int index )
{
	if (index < k_num_menu_items) {
		m_items[index].click();
	} else {
		// Bad button index
		assert( false );
	}
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::set_resolution( int width )
{
	// close all previous interface windows
	t_window_list::iterator child_window;

	while ((child_window = get_children_begin()) != get_children_end())
		(*child_window)->close();

	switch (width)
	{
		case 800:
			m_bitmaps		= k_bitmaps_800.get();
			m_bitmap_raw	= k_bitmap_raw_800.get();
			break;

		case 1024:
			m_bitmaps		= k_bitmaps_1024.get();
			m_bitmap_raw	= k_bitmap_raw_1024.get();
			break;

		case 1280:
			m_bitmaps		= k_bitmaps_1280.get();
			m_bitmap_raw	= k_bitmap_raw_1280.get();
			break;
	}

	// add background bitmaps
	t_screen_point origin(0,0);
	t_window*      window;

	window = new t_bitmap_raw_window( m_bitmap_raw, origin, this );

	// add buttons
	create_buttons( width );
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
t_button* t_main_menu::create_group( std::string const& button_name, std::string const& text_name, std::string const& text_string,
									t_main_menu::t_item& item, int index, t_button_handler handler, std::string help_keyword )
{	
	t_help_block const&		help = get_help_block( "main_menu" );
	t_screen_rect rect(0,0,100,100);

	t_pixel_24    color(0,0,0);
	t_pixel_24    drop_color(200,200,200);

	t_menu_button*			button;
	t_text_window*			text;
	t_bitmap_layer const*	layer;
	t_screen_point			origin( 0, 0 );

	layer				= m_bitmaps->find( text_name );

	button				= create_menu_button( m_bitmaps, button_name, this, origin, index );
	button->set_click_handler( handler );
	set_help( button, help, help_keyword );
	
	if (layer != NULL)
		rect				= layer->get_rect();

	text				= new t_text_window( get_font( rect.height() ), rect, this, text_string, color);

	text->set_center_horizontal(true);
	text->set_center_vertical(true);
	text->set_drop_shadow(true,drop_color);

	item.set( button , text);
	return button;
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
static t_external_string const k_text_copyright( "copyright.main_menu" );
static t_external_string const k_text_new_game( "new_game.main_menu" );
static t_external_string const k_text_load_game( "load_game.main_menu" );
static t_external_string const k_text_options( "options.main_menu" );
static t_external_string const k_text_quit( "quit.main_menu" );
void t_main_menu::create_buttons( int width )
{
	// Note:  If anything gets added here, remember to update
	// the main_menu item array size (k_num_menu_items)

	m_new_game_button = create_group( "new_game", "new_game_text", k_text_new_game, m_items[0], 0,
				  bound_handler( *this, &t_main_menu::new_game_clicked ), "new_game");
	create_group( "load_game", "load_game_text", k_text_load_game,  m_items[1], 1,
				  bound_handler( *this, &t_main_menu::load_game_clicked ), "load_game");
	create_group( "options", "options_text", k_text_options,   m_items[2], 2,
				  bound_handler( *this, &t_main_menu::options_clicked ), "options");
	create_group( "quit", "quit_text", k_text_quit,  m_items[3], 3,
				  bound_handler( *this, &t_main_menu::quit_clicked ), "quit");

	// Put copyright text up.
	t_text_window*  text_window;
	t_screen_rect	rect;
	int				font_size;

	if( width == 800 )
		font_size = 10;
	else
	if( width == 1024 )
		font_size = 12;
	else
	if( width == 1280 )
		font_size = 14;

	rect = m_bitmaps->find( "copywright_text" )->get_rect();
	text_window = new t_text_window( get_font( font_size ), rect, this, k_text_copyright,
		                             t_pixel_24(255,255,255));
	text_window->set_drop_shadow( true, t_pixel_24(0,0,0));
}

// --------------------------------------------------------
// main menu
// new game selection
// --------------------------------------------------------
static t_external_string const k_text_scenario( "main_menu_scenario.misc" );
static t_external_string const k_text_campaign( "main_menu_campaign.misc" );
static t_external_string const k_text_tutorial( "main_menu_tutorial.misc" );

static void menu_unimplemented()
{
	ok_dialog( "Not yet implemented." );
}

void t_main_menu::new_game_clicked( t_button* button )
{
	t_scroll_menu* menu = new t_scroll_menu( this );

	button = m_new_game_button;
	menu->add_item( k_text_scenario, bound_handler( *this, &t_main_menu::start_scenario ));
	menu->add_item( k_text_campaign, bound_handler( *this, &t_main_menu::start_campaign ));
	menu->add_item( k_text_tutorial, bound_handler( *this, &t_main_menu::start_tutorial ));
	menu->open( to_client( button->get_screen_rect() ).top_left() );
}

void t_main_menu::start_campaign()
{
	t_window_ptr ref = this;

	t_adventure_map_ptr adventure_map;
	if( start_new_campaign( adventure_map ) )
	{
		close();
		launch_new_game( adventure_map );
	}
}

void t_main_menu::start_scenario()
{
	start_new_game();
}

void t_main_menu::start_tutorial()
{
	t_window_ptr			parent = get_parent();
	std::string             file_name;

	// create the file path for the tutorial map
	file_name = get_current_folder();
	if (file_name[file_name.length()-1] != '\\')
		file_name += '\\';
	file_name += "maps\\tutorial.h4c";

	t_campaign_file_ref file_ref( k_standard_campaign_tutorial );

	t_single_scenario_campaign_file_header_ptr file_header_ptr =
		create_single_scenario_campaign_file_header( file_ref, 0 );
	if ( file_header_ptr.get() == 0 )
	{
		file_open_failure( file_ref );
		return;
	}

	t_campaign_file_header&		file_header = *file_header_ptr;
	t_map_header const &		map_header = file_header.get_map_header(0);
	std::vector<t_player_setup>	setup;
	
	t_counted_ptr<t_new_map_options_dialog> options_dialog;
		
	setup.resize(map_header.players);

	for( int i = 0; i < map_header.players; i++ )
	{
		if( map_header.can_be_human[i] )
		{
			setup[i].name = "Squire";
			setup[i].human = true;
			setup[i].color = static_cast<t_player_color>(i);
			setup[i].alignment = k_town_life;
		}
		else
		{
			setup[i].name = "Computer Squire";
			setup[i].human = false;
			setup[i].color = static_cast<t_player_color>(i);
			setup[i].alignment = k_town_death;
		}
	}

	options_dialog = new t_new_map_options_dialog( parent, map_header );
	if (!options_dialog->run_modal())
		return ;

	t_adventure_map_ptr adventure_map = read_game_file(	parent, 
				file_header, file_ref, 0, k_difficulty_easy,
				&(*setup.begin()), 0, t_carryover_data_ptr(), true );

	launch_game( adventure_map );
}

// --------------------------------------------------------
// start new campaign
// --------------------------------------------------------
bool start_new_campaign( t_adventure_map_ptr & adventure_map )
{
//	t_window_ptr parent = get_parent();
	t_window_ptr parent = t_window::get_main_window();

	// campaign selection dialog
	t_counted_ptr<t_campaign_selection_dialog> campaign_selection_dialog;
	campaign_selection_dialog = new t_campaign_selection_dialog( t_window::get_main_window() );
	if( campaign_selection_dialog->run_modal() )
	{
		t_standard_campaign_id campaign_id = campaign_selection_dialog->get_campaign_id();
		t_difficulty difficulty = campaign_selection_dialog->get_difficulty();
		t_multi_scenario_campaign_file_header_ptr file_header_ptr = campaign_selection_dialog->get_file_header_ptr();	
		t_map_header const & map_header = file_header_ptr->get_map_header( 0 );
		bool guards_can_move = campaign_selection_dialog->guards_can_move();


		// run the 1st file of the newly selected campaign
		std::vector<t_player_setup> player_setups;
		create_default_player_setup_vector( map_header ).swap( player_setups );

		adventure_map = read_game_file( parent, *file_header_ptr, campaign_id, 0, difficulty, 
										&player_setups[0], 0, 
										t_carryover_data_ptr(), guards_can_move );
		return true;
	}

	return false;
}

void launch_new_game( t_adventure_map_ptr adventure_map )
{
	// Close down any previous sounds
	close_active_sounds();

	t_adventure_frame* adventure_frame = new t_adventure_frame( adventure_map, t_window::get_main_window());	
	adventure_frame->start_new_game( adventure_map );
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::launch_game( t_adventure_map_ptr adventure_map )
{
	t_window_ptr ref = this;

	close();
	launch_new_game( adventure_map );
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::start_new_game()
{
	t_window_ptr						parent = get_parent();
	t_adventure_map_ptr					adventure_map;

	{
		t_item_locker	    locker(m_items, 0);
		adventure_map = read_new_game( parent );
		if (adventure_map == 0)
			return;
	}

	launch_game( adventure_map );
}

// --------------------------------------------------------
// load a new game
// --------------------------------------------------------
extern t_external_string const k_text_read_failed;
t_external_string const        k_text_loading_label( "loading.dialog" );

t_adventure_map_ptr read_game_file( t_window*					parent,
								    t_campaign_file_header&		file_header, 
									t_campaign_file_ref const &	file_ref,
									int							map_number,
									t_difficulty				player_difficulty,
									t_player_setup*				player_setup_ptr,
									int							turn_duration_index,
									t_carryover_data_ptr		carryover_data,
									bool						guards_move )
{
	// Close down any previous sounds
	close_active_sounds();

	t_owned_ptr< std::streambuf > file_ptr = open_campaign_file( file_ref );
	if ( file_ptr.get() == 0 )
	{
		file_open_failure( file_ref );
		return NULL;
	}

	t_progress_bar_dialog*	progress_bar = new t_progress_bar_dialog( parent, k_text_loading_label );
	t_progress_handler*		handler = progress_bar->get_handler();
	bool                    result;
	t_adventure_map_ptr		adventure_map;
	t_game_application::set_cursor_visible( false );

	try
	{

		// find raw size
		int raw_size;

		file_ptr->pubseekpos( file_header.get_map_data_end( map_number ) - std::streambuf::off_type( 4 ) );
		raw_size = get<int>( *file_ptr );
		file_ptr->pubseekpos( file_header.get_map_data_start( map_number ) );

		t_map_header const & map_header = file_header.get_map_header( map_number );

		t_inflate_filter buffer( *file_ptr );

		// create and read a new map

		handler->set_maximum( raw_size );
	
		adventure_map = new t_adventure_map();
		result = adventure_map->read_from_map( buffer,
										   file_ref,
										   map_number,
										   file_header.is_multi_scenario(),
										   handler, 
			                               player_setup_ptr,
                                           player_difficulty,
                                           turn_duration_index,
										   carryover_data, guards_move );
	}
	catch(...)
	{
		result = 0;
	}

	t_game_application::set_cursor_visible( true );
	progress_bar->close();
	if (!result)
	{	   
		ok_dialog( replace_keywords(k_text_read_failed,"%file", file_header.get_name() ), true );
		return NULL;
	}

	clear_pending_messages();
	return adventure_map;
}

// --------------------------------------------------------
// load a new game
// --------------------------------------------------------
t_adventure_map_ptr read_new_game( t_window* parent )
{
	t_counted_ptr<t_new_map_dialog> dialog = new t_new_map_dialog( parent );

	if (!dialog->run_modal())
		return NULL;
	else
		return dialog->get_adventure_map();
}


// --------------------------------------------------------
// load a saved game
// --------------------------------------------------------

t_adventure_map_ptr read_saved_game( t_window* parent )
{
	t_counted_ptr<t_dialog_load_game> dialog;

	dialog = new t_dialog_load_game( parent );
	if (!dialog->run_modal())
		return 0;

	t_saved_game_header const&  header = dialog->get_header();
	std::filebuf				file;
	std::string					file_name = dialog->get_full_name();

	if (file.open( file_name.c_str(), std::ios::in | std::ios::binary ) == 0)
	{
		file_open_failure( file_name );
		return 0;
	}
	// create and read a new map
	t_progress_bar_dialog*	progress_bar = new t_progress_bar_dialog( parent, k_text_loading_label );
	t_progress_handler*		handler = progress_bar->get_handler();
	t_inflate_filter		stream( file );
	bool                    result;
	t_adventure_map_ptr		adventure_map;
	t_game_application::set_cursor_visible( false );

	try
	{
		adventure_map = new t_adventure_map( header.size, header.levels, header.map_random_seed,
                            header.player_difficulty, header.turn_duration_index, 
							header.guards_can_move );
		result = adventure_map->read( stream, handler );
	}
	catch(...)
	{
		result = 0;
	}
	t_game_application::set_cursor_visible( true );
	progress_bar->close();
	if (!result)
	{
	    ok_dialog( replace_keywords(k_text_read_failed,"%file",file_name), true );
		return 0;
	}

	clear_pending_messages();
	return adventure_map;
}

// --------------------------------------------------------
// Restart a game.  Needs adventure_map pointer.
// --------------------------------------------------------
t_adventure_map_ptr read_restarted_game( t_window* parent, t_adventure_map* map )
{
	// First get the file header
	t_campaign_file_ref const & file_ref = map->get_file_ref();
	t_campaign_file_header_ptr file_header_ptr = create_campaign_file_header( file_ref, 0 );
	if ( file_header_ptr.get() == 0 )
	{
		file_open_failure( file_ref );
		return 0;
	}

	// Now rebuild the player setup array
	t_map_header const & map_header = file_header_ptr->get_map_header( map->get_map_number() );
	t_player_list const & players = map->get_players();

	std::vector< t_player_setup > player_setups;

	t_player_color color;
	for ( color = t_player_color( 0 ); color < k_active_player_color_count; enum_incr( color ) )
	{
		if ( !map_header.playable[ color ] )
			continue;

		t_player_list::const_iterator player_ptr_iter = players.begin();
		for ( ; true; ++player_ptr_iter )
		{
			assert( player_ptr_iter != players.end() );
			if ( ( *player_ptr_iter )->get_color() == color )
				break;
		}

		t_player const & player = **player_ptr_iter;

		t_player_setup setup;
		setup.name = player.get_name();
		setup.human = !player.is_computer();
		setup.color = color;
		setup.alignment = player.get_alignment();
		player_setups.push_back( setup );
	}
	assert( !player_setups.empty() );

	// Read the file to create the map
	return	read_game_file(
				parent,
				*file_header_ptr,
				file_ref,
				map->get_map_number(),
				map->get_player_difficulty(),
				&player_setups[ 0 ],
				map->get_turn_duration_index(),
				map->get_carry_in_data(),
				map->guards_can_move() );
}

// --------------------------------------------------------
// Read the next scenario in a multi scenario campaign
// --------------------------------------------------------
t_adventure_map_ptr read_next_scenario( t_window* parent, t_adventure_map & map, bool * no_more_maps )
{
	assert( map.is_multi_scenario() );

	// Start by clearing the complete flag (if one was provided)
	if (no_more_maps)
		*no_more_maps = false;

	// First get the file header
	t_campaign_file_ref const & file_ref = map.get_file_ref();
	t_multi_scenario_campaign_file_header_ptr file_header_ptr =
		create_multi_scenario_campaign_file_header( file_ref, 0 );
	if ( file_header_ptr.get() == 0 )
	{
		file_open_failure( file_ref );
		return 0;
	}

	t_map_header const & header = file_header_ptr->get_map_header( map.get_map_number() );

	std::string epilogue_text = header.epilogue_info.get_text();
	// If at the very least, we have text to show, do this
	if( !epilogue_text.empty() )
	{
		// Run the campaign epilogue if there is something to display for this map
		t_counted_ptr< t_multi_scenario_dialog > dialog_ptr(
			new t_multi_scenario_dialog( t_window::get_main_window(), file_header_ptr, map.get_map_number(), false ) );
		dialog_ptr->run_modal();
	}

	int map_number = map.get_map_number() + 1;

	if ( map_number >= file_header_ptr->get_map_count() )
	{
		// Set the complete flag (if one was provided)
		if (no_more_maps)
			*no_more_maps = true;
		return 0;
	}

	t_counted_ptr< t_multi_scenario_dialog > dialog_ptr(
		new t_multi_scenario_dialog( t_window::get_main_window(), file_header_ptr, map_number, true, &map ) );
	if ( !dialog_ptr->run_modal() )
		return 0;

	// Create the player setup vector
	std::vector< t_player_setup > player_setups;
	create_default_player_setup_vector( file_header_ptr->get_map_header( map_number ) ).swap( player_setups );

	// Read the file to create the map
	return	read_game_file(
				parent,
				*file_header_ptr,
				file_ref,
				map_number,
				map.get_player_difficulty(),
				&player_setups[ 0 ],
				0,
				map.build_carry_out_data(),
				map.guards_can_move() );
}

// --------------------------------------------------------
// launch a saved game
// --------------------------------------------------------
void launch_saved_game( t_adventure_map_ptr adventure_map )
{
	t_adventure_frame* adventure_frame = new t_adventure_frame( adventure_map, t_window::get_main_window() );
	
	adventure_frame->start_saved_game();
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::load_game_clicked( t_button * )
{
	t_window_ptr						parent = get_parent();
	t_adventure_map_ptr					adventure_map;

	{
		t_item_locker		locker(m_items, 1);
		adventure_map = read_saved_game( parent );
		if (adventure_map == 0)
			return;
	}

	t_window_ptr ref = this;

	close();
	launch_saved_game( adventure_map );
}


// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::on_size_change( t_screen_rect const& rect )
{
	set_resolution( rect.width() );
}


// --------------------------------------------------------
// Enter the UI -- FOR NOW JUST FIRE OFF THE TESTING CODEPATH
// --------------------------------------------------------

static t_external_string const k_text_settings( "main_menu_settings.misc" );
static t_external_string const k_text_high_score( "main_menu_high_score.misc" );
static t_external_string const k_text_replay_intro( "main_menu_replay_intro.misc" );
static t_external_string const k_text_credits( "main_menu_credits.misc" );

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::options_clicked( t_button* button )
{
	t_scroll_menu* menu = new t_scroll_menu( this );

	menu->add_item( k_text_settings, bound_handler( *this, &t_main_menu::settings_clicked ));
	menu->add_item( k_text_high_score, bound_handler( *this, &t_main_menu::high_score_clicked ));
	menu->open( to_client( button->get_screen_rect() ).top_left() );
}
// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::settings_clicked()
{
	t_item_locker				    locker(m_items, 2);
	t_counted_ptr<t_options_dialog> dialog = new t_options_dialog( this );

	if (!dialog->run_modal())
		return;

	switch (dialog->get_resolution())
	{
		case 800:
			::set_resolution( 800, 600, true );
			move( t_screen_rect(0,0,800,600) );
			break;

		case 1024:
			::set_resolution( 1024, 768, true );
			move( t_screen_rect(0,0,1024,768) );
			break;

		case 1280:
			::set_resolution( 1280, 1024, true );
			move( t_screen_rect(0,0,1280,1024) );
			break;
	}
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
void t_main_menu::high_score_clicked()
{
	t_window_ptr			parent = get_parent();
	t_high_scores_ptr		high_scores = read_high_scores_file();

	if( high_scores )
	{
		t_counted_ptr<t_high_score_dialog> dialog;
		dialog = new t_high_score_dialog( parent, *high_scores );
		dialog->run_modal();
	}
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
extern t_external_string const k_text_do_you_want_to_quit;
t_external_string const k_text_do_you_want_to_quit( "ask_quit" );

void t_main_menu::quit_clicked( t_button* )
{
	t_item_locker locker(m_items, 5);

	if (yes_no_dialog( k_text_do_you_want_to_quit )) {
		t_game_application::exit(0);
	}
}

// --------------------------------------------------------
// main menu
// --------------------------------------------------------
bool t_main_menu::menu_click( int id )
{
	switch (id)
	{
		case k_id_file_new_scenario:
			new_game_clicked( 0 );
			return true;

		case k_id_file_load_game:
			load_game_clicked( 0 );
			return true;

		case k_id_file_exit:
			quit_clicked( 0 );
			return true;

		case k_id_verify_strings:
			verify_external_strings();
			return true;
	}
	return false;
}